#define MAX_RACES			10
#define MAX_RACE_PLAYERS	4
#define MAX_RACE_COUNTDOWN  20

new
	bool:RaceIdUsed[MAX_RACES]=false,
	JoinCP[MAX_RACES],
	Text3D:JoinLabel[MAX_RACES],
	RaceFile[MAX_RACES][30],

	BestP[24],
	BestTime[15],
	BestMS,
	BestS,
	BestM,
	Float:FinishPos[3],
	Float:StartSlots[MAX_RACE_PLAYERS][4],
	SlotUsage[MAX_RACE_PLAYERS],
	RaceActive=-1,

	bool:RaceStarted,

	RaceCountDown,
	Text:RaceCountDownText,
	Text:RaceDistanceCount[MAX_PLAYERS],
	MaxRacePlayers,
	FinishLine[MAX_RACE_PLAYERS],
	RaceInitialTick[MAX_RACE_PLAYERS],
	RaceWinner=-1,
	Place,
	TotalRaces,
	RaceFinishLocation,
	Float:FinishLocation[10][3]=
	{
		{-2504.467041, 2420.883789, 16.249454},
		{-221.315994, 2634.838378, 62.516883},
		{2048.720947, 1545.601196, 10.503570},
		{-2853.802001, 465.324096, 4.102130},
		{225.974609, 970.993408, 27.908227},
		{2340.568115, 320.036682, 32.374656},
		{-1762.798339, -580.206115, 16.058029},
		{-2144.647216, -2411.305419, 30.184822},
		{86.070411, -1536.633300, 5.259685},
		{2866.315429, -1658.848632, 10.591567}
	},
	RaceFinish[10][33]=
	{
		"Bayside",
		"Las Payasdas",
		"Las Venturas Strip",
		"San Fierro Westside",
		"Fort Carson Cluckin Bell",
		"Palomino Creek Freeway Junction",
		"Easter Bay Airport Entrance",
		"Angel Pine Freeway Junction",
		"Los Santos West Bridge",
		"Los Santos Stadium"
	};

script_Race_DistanceUpdate(playerid)
{
	new str[40], Float:dist, Float:pos[3];
	GetPlayerPos(playerid, pos[0], pos[1], pos[2]);
	dist=GetDist3D(pos[0], pos[1], pos[2], FinishPos[0], FinishPos[1], FinishPos[2]);
	format(str, 40, "Distance To Finish: %.2fm", dist);
	TextDrawSetString(RaceDistanceCount[playerid], str);
	TextDrawShowForPlayer(playerid, RaceDistanceCount[playerid]);
}


public OnPlayerEnterDynamicRaceCP(playerid, checkpointid)
{
	for(new i=0;i<TotalRaces;i++)
	{
	    if(checkpointid == JoinCP[i] && !(bPlayerGameSettings[playerid]&InRace))
	    {
	    	if(bPlayerGameSettings[playerid]&parkour)return 1;
	        if(IsPlayerInAnyVehicle(playerid))
	        {
	            if(pInRace()==MaxRacePlayers && pInRace()!=0)msg(playerid, RED, "Race is full!");
				else if(RaceStarted)msg(playerid, RED, "There is already a race in progress");
	        	else ShowPlayerDialog(playerid, d_RaceJoin, DIALOG_STYLE_MSGBOX, "Join Race", "Do you want to join this race?", "Join", "Cancel"),RaceActive=i;
	        }
	        else msg(playerid, RED, "You must be in a vehicle");

			break;
	    }
	}
	if(checkpointid==FinishLine[playerid])
	{
		new
			ms,
			m,
			s,
			pTime[15];
		ms=GetTickCount()-RaceInitialTick[playerid];
    	m=(ms%(1000*60*60))/(1000*60),s=((ms%(1000*60*60))%(1000*60))/1000,ms=ms-(m*60*1000)-(s*1000);
		if(s<10)format(pTime, 15, "%d:0%d.%d", m, s, ms);
		else	format(pTime, 15, "%d:%d.%d", m, s, ms);

	    if(RaceWinner==-1)
		{
			msgaF(YELLOW, "%s won the race! time: %s", GetName(playerid), pTime);
			file_Open(RaceFile[RaceActive]);
			if(file_IsKey("bestP"))
			{
				if(m>=BestM)
				{
				    if(s>=BestS)
				    {
				        if(ms>=BestMS)msgF(playerid, YELLOW, "You didn't beat the best time of %s", BestTime);
				        else BeatenBest(playerid, m, s, ms);
				    }
				    else BeatenBest(playerid, m, s, ms);
				}
				else BeatenBest(playerid, m, s, ms);
			}
			else BeatenBest(playerid, m, s, ms);
			file_Save(RaceFile[RaceActive]);
			file_Close();
			RaceWinner=playerid;
		}
	    else msgaF(YELLOW, "%s finished the race in %s Place, time: %s", GetName(playerid), Numerical(Place+1), pTime);
		Place++;
		DestroyDynamicRaceCP(FinishLine[playerid]);
		SetPlayerVirtualWorld(playerid, FREEROAM_WORLD);
		SetVehicleVirtualWorld(GetPlayerVehicleID(playerid), FREEROAM_WORLD);
		bitFalse(bPlayerGameSettings[playerid], InRace);
		TextDrawHideForPlayer(playerid, RaceDistanceCount[playerid]);
		if(pInRace()==0)EndRace();
	    return 1;
	}
	return 0;
}
BeatenBest(playerid, m, s, ms)
{
	new str[128];
	file_SetStr("bestP", GetName(playerid));
	file_SetVal("bestMS", ms);
	file_SetVal("bestS", s);
	file_SetVal("bestM", m);
	if(!strcmp(BestP, GetName(playerid)))msgaF(YELLOW, "%s: %d.%d:%d beaten their best time of %s", GetName(playerid), m, s, ms, BestTime);
	else msgaF(YELLOW, "%s: %d.%d:%d beaten original best time by %s (%s)", GetName(playerid), m, s, ms, BestP, BestTime);
	new RaceName[50], loc=strfind(RaceFile[RaceActive], ".ini");
	RaceName = RaceFile[RaceActive];
	strdel(RaceName, loc, strlen(RaceName));
	format(str, 128, "%s\n%s - %d.%d:%d\n\nFinish: %s", RaceName, GetName(playerid), m, s, ms, RaceFinish[RaceFinishLocation]);
	UpdateDynamic3DTextLabelText(JoinLabel[RaceActive], YELLOW, str);
}
script_Race_OnDialogResponse(playerid, dialogid, response)
{
	if(dialogid == d_RaceJoin)
	{
		if(!response)return 0;
		new slot;
		if(pInRace()>0)
		{
			while(SlotUsage[slot]!=-1)slot++;
			if(slot==MaxRacePlayers) msg(playerid, RED, "Race Is Full");
			else
			{
				RaceCountDown=MAX_RACE_COUNTDOWN;
				TextDrawShowForAll(RaceCountDownText);
				JoinRace(playerid, slot);
			}
		}
		else
		{
		    slot=0;
			LoadRace();
			msga(YELLOW, "Race Is Waiting, need one more player");
			RaceCountDown=0;
			TextDrawSetString(RaceCountDownText, "Race Waiting...");
			TextDrawShowForAll(RaceCountDownText);
			JoinRace(playerid, slot);
			if(!response)
			{
				RaceActive=-1;
				return 1;
			}
		}
	}
	return 0;
}

CMD:leaverace(playerid, params[])
{
	if(bPlayerGameSettings[playerid]&InRace)
	{
		LeaveRace(playerid);
		msg(playerid, YELLOW, "Left current race");
	}
	else msg(playerid, RED, "You aren't in a race");
	return 1;
}


LoadRace()
{
	new slotstr[6];
	if(!fexist(RaceFile[RaceActive]))return printf("File Not Found: %s", RaceFile[RaceActive]);
	file_Open(RaceFile[RaceActive]);
	MaxRacePlayers=file_GetVal("MaxPlayers");
	RaceFinishLocation=file_GetVal("FinishPos");
	FinishPos[0]=FinishLocation[RaceFinishLocation][0],
	FinishPos[1]=FinishLocation[RaceFinishLocation][1],
	FinishPos[2]=FinishLocation[RaceFinishLocation][2];
	for(new i;i<MaxRacePlayers;i++)
	{
	    format(slotstr, 6, "Slot%d", i);
		sscanf(file_GetStr(slotstr), "p<,>ffff", StartSlots[i][0], StartSlots[i][1], StartSlots[i][2], StartSlots[i][3]);
	}
	if(file_IsKey("bestP"))
	{
	    format(BestP, 24, file_GetStr("bestP"));
	    BestM=file_GetVal("bestM");
	    BestS=file_GetVal("bestS");
	    BestMS=file_GetVal("bestMS");
		format(BestTime, 15, "%d:%d.%d", BestM, BestS, BestMS);
	}
	file_Close();
	return 1;
}
JoinRace(playerid, slot)
{
	SlotUsage[slot]=playerid;
	SetVehicleVirtualWorld(GetPlayerVehicleID(playerid), RACE_WORLD);
	SetPlayerVirtualWorld(playerid, RACE_WORLD);
	SetVehiclePos(GetPlayerVehicleID(playerid), StartSlots[slot][0], StartSlots[slot][1], StartSlots[slot][2]);
	SetVehicleZAngle(GetPlayerVehicleID(playerid), StartSlots[slot][3]);
	TogglePlayerControllable(playerid, false);
	SetCameraBehindPlayer(playerid);
	bitTrue(bPlayerGameSettings[playerid], InRace);
	msg(playerid, ORANGE, FormatColours("Type "#C_YELLOW"'/leaverace' "#C_ORANGE"to leave the race"));
}
LeaveRace(playerid)
{
	DestroyDynamicRaceCP(FinishLine[playerid]);
	SetPlayerVirtualWorld(playerid, FREEROAM_WORLD);
	SetVehicleVirtualWorld(GetPlayerVehicleID(playerid), FREEROAM_WORLD);
	bitFalse(bPlayerGameSettings[playerid], InRace);
	TextDrawHideForPlayer(playerid, RaceDistanceCount[playerid]);
	TextDrawHideForPlayer(playerid, RaceCountDownText);
	TogglePlayerControllable(playerid, true);
	if(pInRace()==0)EndRace();
	for(new i;i<MAX_RACE_PLAYERS;i++)
	{
		if(SlotUsage[i]==playerid)
		{
			SlotUsage[i]=-1;
			break;
		}
	}
}
RaceCountTick()
{
	new str[120];
	format(str, 120, "Race Starting In %d", RaceCountDown);
	TextDrawSetString(RaceCountDownText, str);
	TextDrawShowForAll(RaceCountDownText);
    RaceCountDown--;
	if(RaceCountDown==0)StartRace();
}
StartRace()
{
	new id;
	for(new slot;slot<MaxRacePlayers;slot++)
	{
		id=SlotUsage[slot];
		if(id!=-1)
		{
		    TogglePlayerControllable(id, true);
		    GameTextForPlayer(id, "~r~GO!!", 3000, 5);
			FinishLine[id]=CreateDynamicRaceCP(1, FinishPos[0], FinishPos[1], FinishPos[2], 0, 0, 0, 8.0, RACE_WORLD, _, id, 1000.0);
			RaceInitialTick[id]=GetTickCount();
			TextDrawShowForPlayer(id, RaceDistanceCount[id]);
		}
	}
	RaceStarted=true;
	TextDrawHideForAll(RaceCountDownText);
}
EndRace()
{
	RaceActive=-1,
	RaceStarted=false,
	RaceWinner=-1,
	Place=0;
	for(new s;s<MAX_RACE_PLAYERS;s++)SlotUsage[s]=-1;
	TextDrawHideForAll(RaceCountDownText);
}
pInRace()
{
	new r;
	PlayerLoop(i)if(bPlayerGameSettings[i]&InRace)r++;
	return r;
}
